package controller;

import bean.Article;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.annotation.MultipartConfig;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import service.ArticleService;
import dao.util.ThymeleafView;
import bean.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.List;

@WebServlet(urlPatterns = {"/articles", "/articles/recommend", "/articles/detail", "/articles/create", 
        "/articles/update", "/articles/delete", "/articles/get"})
@MultipartConfig
public class ArticleController extends HttpServlet {

    private final ArticleService articleService = new ArticleService();
    private static final Logger log = LoggerFactory.getLogger(ArticleController.class);

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String uri = req.getRequestURI();
        if (uri.endsWith("/articles")) {
            List<Article> list = articleService.listAll();
            ThymeleafView.render("index", req, resp, java.util.Map.of("articles", list));
        } else if (uri.endsWith("/recommend")) {
            List<Article> r = articleService.recommend(2);
            ThymeleafView.render("recommend", req, resp, java.util.Map.of("recommend", r));
        } else if (uri.endsWith("/detail")) {
            String idStr = req.getParameter("id");
            Integer id = idStr == null ? null : Integer.valueOf(idStr);
            Article a = id == null ? null : articleService.getById(id);
            ThymeleafView.render("article-detail", req, resp, java.util.Map.of("article", a));
        } else if (uri.endsWith("/get")) {
            String idStr = req.getParameter("id");
            Integer id = idStr == null ? null : Integer.valueOf(idStr);
            Article a = id == null ? null : articleService.getById(id);
            resp.setContentType("application/json;charset=UTF-8");
            if (a == null) {
                resp.getWriter().write("{\"success\":false,\"error\":\"not_found\"}");
            } else {
                String json = String.format(java.util.Locale.ROOT,
                        "{\"success\":true,\"data\":{\"id\":%d,\"title\":%s,\"content\":%s,\"tags\":%s,\"categoryId\":%s,\"authorId\":%s}}",
                        a.getId(),
                        toJsonString(a.getTitle()),
                        toJsonString(a.getContent()),
                        toJsonString(a.getTags()),
                        a.getCategoryId() == null ? "null" : a.getCategoryId().toString(),
                        a.getAuthorId() == null ? "null" : a.getAuthorId().toString());
                resp.getWriter().write(json);
            }
        } else {
            resp.sendError(404);
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        String uri = req.getRequestURI();
        if (uri.endsWith("/create")) {
            Article a = new Article();
            a.setTitle(req.getParameter("title"));
            a.setContent(req.getParameter("content"));
            a.setCategoryId(parseIntOrNull(req.getParameter("categoryId")));
            // 优先从 session 用户设置作者ID，避免未填写导致插入失败
            User currentUser = null;
            if (req.getSession(false) != null) {
                currentUser = (User) req.getSession(false).getAttribute("user");
            }
            Integer authorIdParam = parseIntOrNull(req.getParameter("authorId"));
            a.setAuthorId(currentUser != null ? currentUser.getId() : authorIdParam);
            // 标题与内容为必填，multipart/form-data 下未加 @MultipartConfig 时 getParameter 会返回 null
            if (a.getTitle() == null || a.getTitle().trim().isEmpty()) {
                if (isAjax(req)) {
                    resp.setContentType("application/json;charset=UTF-8");
                    resp.getWriter().write("{\"success\":false,\"error\":\"missing_title\",\"message\":\"标题不能为空\"}");
                    return;
                } else {
                    resp.sendError(400, "标题不能为空");
                    return;
                }
            }

            if (a.getAuthorId() == null) {
                if (isAjax(req)) {
                    resp.setContentType("application/json;charset=UTF-8");
                    resp.getWriter().write("{\"success\":false,\"error\":\"missing_author_id\",\"message\":\"请先登录或填写作者ID\"}");
                    return;
                } else {
                    resp.sendError(400, "缺少作者ID，请先登录或在表单中填写作者ID");
                    return;
                }
            }
            a.setTags(req.getParameter("tags"));
            int r = 0;
            String err = null;
            try {
                log.info("准备发布文章: title={}, authorId={}, categoryId={}", a.getTitle(), a.getAuthorId(), a.getCategoryId());
                r = articleService.add(a);
            } catch (Exception e) {
                err = e.getMessage();
                log.error("发布文章失败: {}", err, e);
            }
            if (isAjax(req)) {
                resp.setContentType("application/json;charset=UTF-8");
                if (r > 0) {
                    Integer newId = a.getId();
                    String idVal = newId == null ? "null" : newId.toString();
                    resp.getWriter().write("{\"success\":true,\"id\":" + idVal + "}");
                } else {
                    String msg = err == null ? "insert_failed" : err.replace("\"", "\\\"");
                    resp.getWriter().write("{\"success\":false,\"error\":\"" + msg + "\"}");
                }
            } else {
                if (r > 0) {
                    Integer newId = a.getId();
                    if (newId != null) {
                        resp.sendRedirect(req.getContextPath() + "/articles/detail?id=" + newId);
                    } else {
                        resp.sendRedirect(req.getContextPath() + "/articles");
                    }
                } else {
                    resp.sendError(500, err == null ? "Publish failed" : err);
                }
            }
        } else if (uri.endsWith("/update")) {
            Article a = new Article();
            a.setId(parseIntOrNull(req.getParameter("id")));
            a.setTitle(req.getParameter("title"));
            a.setContent(req.getParameter("content"));
            a.setCategoryId(parseIntOrNull(req.getParameter("categoryId")));
            a.setAuthorId(parseIntOrNull(req.getParameter("authorId")));
            a.setTags(req.getParameter("tags"));
            int r = articleService.update(a);
            resp.setContentType("application/json;charset=UTF-8");
            resp.getWriter().write(r > 0 ? "{\"success\":true}" : "{\"success\":false}");
        } else if (uri.endsWith("/delete")) {
            Integer id = parseIntOrNull(req.getParameter("id"));
            int r = (id == null) ? 0 : articleService.delete(id);
            resp.setContentType("application/json;charset=UTF-8");
            resp.getWriter().write(r > 0 ? "{\"success\":true}" : "{\"success\":false}");
        } else {
            resp.sendError(404);
        }
    }

    private static boolean isAjax(HttpServletRequest req) {
        String xrw = req.getHeader("X-Requested-With");
        String accept = req.getHeader("Accept");
        return (xrw != null && xrw.equalsIgnoreCase("XMLHttpRequest"))
                || (accept != null && accept.toLowerCase(java.util.Locale.ROOT).contains("application/json"));
    }

    private static String toJsonString(String s) {
        if (s == null) return "null";
        String escaped = s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n");
        return '"' + escaped + '"';
    }

    private static Integer parseIntOrNull(String s) {
        if (s == null) return null;
        s = s.trim();
        if (s.isEmpty()) return null;
        try { return Integer.valueOf(s); } catch (NumberFormatException e) { return null; }
    }
}